package com.dayu.finecomm.dsc;

import io.netty.channel.Channel;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dayu.finecomm.dsc.protocol.DDP;
import com.dayu.finecomm.dsc.protocol.DDP.DDPPack;
import com.dayu.finecomm.dsc.protocol.DDP.DSCSendData;

/**
 * DTU代理管理，对DTU代理的创建、移除、事件处理等工作
 * 
 * @author hddz
 * @since 2017-07-27 16:20:20
 * @version V1.0
 */
public class DTUProxyManager {
	static Logger LOGGER = LoggerFactory.getLogger(DTUProxyManager.class);

	/**
	 * 单例模式
	 */
	private volatile static DTUProxyManager mSelf = null;

	/**
	 * DDP协议解析器
	 */
	private DDP mDDP = null;

	/**
	 * 保存DTU代理 DTUProxy (DTU Identify -> DTUProxy)
	 */
	private Map<String, DTUProxy> mDTUProxys;

	/**
	 * remote address
	 */
	private Map<String, String> mDTUSockets;

	/**
	 * 保存DTU Identify
	 */
	private List<String> mIdentifyList;

	/**
	 * 当前DTUProxy 最大ID号，一次递增
	 */
	int mCurProxyID;

	/**
	 * 创建DSC单例
	 * 
	 * @return DSC
	 */
	public static DTUProxyManager getInstance() {
		if (null == mSelf) {
			synchronized (DTUProxyManager.class) {
				if (null == mSelf) {
					mSelf = new DTUProxyManager();
				}
			}
		}

		return mSelf;
	}

	private DTUProxyManager() {
	}

	/**
	 * 初始化DTUProxyManager
	 */
	public void init() {
		mCurProxyID = 0;

		mDDP = new DDP();
		mDTUProxys = new HashMap<>();
		mDTUSockets = new HashMap<>();
		mIdentifyList = new ArrayList<>();
	}

	/**
	 * 销毁DTUProxyManager
	 */
	public void uninit() {
		mCurProxyID = 0;

		Iterator<Entry<String, DTUProxy>> iter = mDTUProxys.entrySet()
				.iterator();
		while (iter.hasNext()) {
			Map.Entry<String, DTUProxy> entry = (Map.Entry<String, DTUProxy>) iter
					.next();
			DTUProxy dtu = (DTUProxy) entry.getValue();
			dtu.unregisted();
			dtu.close();
		}

		mDTUProxys.clear();
		mDTUSockets.clear();
		mIdentifyList.clear();
	}

	/**
	 * 创建DTUProxy，有新的DTU连接
	 * 
	 * @param socket
	 *            Remote address
	 * @param channel
	 *            通信通道
	 * @param type
	 *            通信方式 1 - TCP, 2 - UDP
	 * @return 0 - success
	 */
	public DTUProxy createProxy(String identify, String socket,
			Channel channel, int type) {
		DTUProxy dtu = null;

		if (false == mIdentifyList.contains(identify)) {
			LOGGER.info("create new proxy: " + socket + ", identify: "
					+ identify);

			dtu = new DTUProxy(++mCurProxyID, socket, channel, type, identify);

			mDTUProxys.put(identify, dtu);
			mDTUSockets.put(socket, identify);
			mIdentifyList.add(identify);
		}

		return dtu;
	}

	/**
	 * 移除DTUProxy，该DTU已经断开
	 * 
	 * @param socket
	 */
	public void removeProxy(String socket) {
		String identify = "";

		LOGGER.info("remove proxy: " + socket);

		if (true == mDTUSockets.containsKey(socket)) {
			identify = mDTUSockets.get(socket);
		}

		if (null != identify && false == identify.isEmpty()) {
			if (true == mDTUProxys.containsKey(identify)) {
				mDTUProxys.remove(identify);
			}

			if (true == mIdentifyList.contains(identify)) {
				mIdentifyList.remove(identify);
			}

			mDTUSockets.remove(socket);
		}
	}

	/**
	 * 获取所有DTU设备的数量
	 * 
	 * @return
	 */
	public int getTotalDTU() {
		return mIdentifyList.size();
	}

	/**
	 * 获取所有DTU设备的Identify
	 * 
	 * 
	 * @return List<String>
	 */
	public List<String> getTotalDtuIdentify() {
		return mIdentifyList;
	}

	/**
	 * 获取DTU身份识别码
	 * 
	 * 
	 * @param index
	 * @return 身份识别码
	 */
	public String getDtuIdentify(int index) {
		String identify = "";

		try {
			identify = mIdentifyList.get(index);
		} catch (IndexOutOfBoundsException e) {
			identify = "";
			LOGGER.error("Index Out Of Bounds for mRemoteAddr:" + index);
		}

		return identify;
	}

	/**
	 * 发送用户数据到DTU
	 * 
	 * @param identify
	 *            DTU identify
	 * @param msg
	 * @return 0 - success, -1 - failed
	 */
	public int sendDataToDTU(String identify, byte[] msg) {
		int ret = -1;

		if (true == mDTUProxys.containsKey(identify)) {
			DTUProxy dtu = (DTUProxy) mDTUProxys.get(identify);

			if (true == dtu.isRegisted()) {
				try {
					DSCSendData dataPack = mDDP.new DSCSendData(
							identify.getBytes(), msg);
					byte[] data = mDDP.pack(dataPack, dtu.getCommType());
					dtu.sendData(data);
					ret = 0;
				} catch (UnknownHostException e) {
					LOGGER.error("UnknownHostException", e);
				}
			}
		}

		return ret;
	}

	/**
	 * 处理DDP包
	 * 
	 * @param socket
	 *            远端网络地址
	 * @param pack
	 *            DDP包
	 * @return DDP 响应包 or null
	 */
	public DDPPack processDDP(String socket, Channel channel, int type,
			DDPPack pack) {
		String identify = null;
		DDPPack ackPack = null;

		LOGGER.debug("DTU->DSC: " + socket);

		if (null == pack) {
			ackPack = mDDP.new DSCInvalid(DDP.getDefaultIdenty());

			LOGGER.info("Unpack DSC message failed");
		} else {
			byte packType = pack.getType();

			switch (packType) {
			case DDP.DTU_PACK_TYPE_REG: // 注册
				identify = new String(pack.getIdenty());

				if (true == mDTUProxys.containsKey(identify)) {

					DTUProxy dtu = (DTUProxy) mDTUProxys.get(identify);
					dtu.reset(socket, channel);
					dtu.registed();

					mDTUSockets.put(socket, identify);
				} else {
					LOGGER.info("NEW DTU(" + identify + ") registed");

					DTUProxy dtu = createProxy(identify, socket, channel, type);
					dtu.registed();
				}

				LOGGER.info("DTU->DSC Register successed: " + socket);

				ackPack = mDDP.new DSCRegAck(pack.getIdenty());
				break;
			case DDP.DTU_PACK_TYPE_UNREG: // 注销
				identify = new String(pack.getIdenty());

				if (true == mDTUProxys.containsKey(identify)) {
					DTUProxy dtu = (DTUProxy) mDTUProxys.get(identify);
					dtu.unregisted();

					ackPack = mDDP.new DSCUnregAck(pack.getIdenty());

					LOGGER.info("UNREG DTU(" + pack.getIdenty() + ") SUCCESS");
				} else {
					ackPack = mDDP.new DSCInvalid(pack.getIdenty());

					LOGGER.info("UNREG DTU(" + pack.getIdenty() + ") ERROR");
				}
				break;
			case DDP.DTU_PACK_TYPE_RECV_ACK:
				ackPack = null;
				LOGGER.info("DTU->DSC(RECV_ACK=" + pack.getType() + "): "
						+ socket);
				break;
			case DDP.DTU_PACK_TYPE_INVALID:
				ackPack = null;
				LOGGER.info("DTU->DSC(INVALID=" + pack.getType() + "): "
						+ socket);
				break;
			case DDP.DTU_PACK_TYPE_SEND_DATA: // 处理用户数据包
				identify = new String(pack.getIdenty());

				if (true == mDTUProxys.containsKey(identify)) {
					DTUProxy dtu = (DTUProxy) mDTUProxys.get(identify);
					if (false == dtu.isRegisted()) { // 未注册设备拒绝接受DTU数据
						ackPack = mDDP.new DSCInvalid(pack.getIdenty());
					} else {
						ackPack = null;
					}
				} else {
					ackPack = mDDP.new DSCInvalid(pack.getIdenty());

					LOGGER.info("SEND Data NOT Contains identify: "
							+ pack.getIdenty());
				}
				break;
			case DDP.DTU_PACK_TYPE_LOG_ACK:
			case DDP.DTU_PACK_TYPE_SETTING_ACK:
			case DDP.DTU_PACK_TYPE_UPGRADE_ACK:
			case DDP.DTU_PACK_TYPE_QUERY_ACK:
				ackPack = mDDP.new DSCInvalid(pack.getIdenty());

				LOGGER.info("This current not support " + packType + ", "
						+ pack.getIdenty());
				break;
			default:
				ackPack = mDDP.new DSCInvalid(DDP.getDefaultIdenty());

				LOGGER.info("Unknown packet " + packType);
				break;
			}
		}

		return ackPack;
	}
}
